#include <glfevent.h>
#include <glfwindow.h>
#include <Windows.h>

#define MAX_EVENTS	8	//MUST BE POT
#define MAX_EVENTS_MINUS_1 (MAX_EVENTS-1)

static int g_init = 0;
static glfEvent g_eventBuffer[ MAX_EVENTS ];
static int g_head = 0;
static int g_tail = 0;
static BYTE g_keyboardstate[ 256 ];

typedef struct
{
	int buttonState;
	int x,y;
	int dx, dy;
} MouseState;

static MouseState g_mousestate;
static POINT g_pt;

int glfPopEvent( glfEvent *e )
{
	if( g_head != g_tail )
	{
		memcpy( e, &g_eventBuffer[ g_head ], sizeof( glfEvent ) );
		++g_head;
		g_head &= MAX_EVENTS_MINUS_1;
		return 1;
	}
	//printf( "Event queue empty\n" );
	return 0;
}

int glfPushEvent( glfEvent *e )
{
	if( g_tail != ( ( g_head - 1 ) & 255 ) )
	{
		memcpy( &g_eventBuffer[ g_tail ], e, sizeof( glfEvent ) );
		++g_tail;
		g_tail &= MAX_EVENTS_MINUS_1;
		return 1;
	}
	//printf( "Event queue full\n" );
	return 0;
}

static void pollMouse( MouseState *ms )
{
	#if defined( GLF_PLATFORM_WIN32 )
	if( ms )
	{
		POINT pt;
		int x,y;
		int ox,oy;
		GetCursorPos( &pt );
		glfGetWindowPosition( &x, &y );
		glfGetDisplayOffset( &ox, &oy );
		x+=ox;
		y+=oy;
	}
	#endif
}

int glfDoEvents()
{
	#if defined( GLF_PLATFORM_WIN32 )
	glfEvent e;
	int i;
	BYTE keyboardstate[ 256 ];
	MouseState mousestate;
	POINT pt ;
	RECT rect;
	int x,y;
	int ox,oy;

	//Process keyboard events
	GetKeyboardState( keyboardstate );
	GetCursorPos( &pt );
	glfGetWindowPosition( &x, &y );
	glfGetDisplayOffset( &ox, &oy );
	x+=ox;
	y+=oy;
	if( g_init == 0 )
	{
		memcpy( g_keyboardstate, keyboardstate, 256 * sizeof( BYTE ) );
		rect.left = x;
		rect.top = y;
		rect.bottom = y+glfGetHeight()-1;
		rect.right = x+glfGetWidth()-1;
		g_mousestate.x = pt.x >= rect.left ? pt.x : rect.left;
		g_mousestate.y = pt.y >= rect.top ? pt.y : rect.top;
		g_mousestate.x = g_mousestate.x < rect.right ? g_mousestate.x : rect.right;
		g_mousestate.y = g_mousestate.y < rect.bottom ? g_mousestate.y : rect.bottom;
		g_mousestate.x -= x;
		g_mousestate.y -= y;
		g_mousestate.dx = 0;
		g_mousestate.dy = 0;
		memcpy( &g_pt, &pt, sizeof( pt ) );
		g_init = 1;
	}
	for( i = 0; i < 256; ++i )
	{
		if( keyboardstate[ i ] != g_keyboardstate[ i ] )
		{
			//If the high-order bit is 1, the key is down; otherwise, it is up.
			//If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.


			//printf( "%u %c %u\n", i, i, keyboardstate[ i ] );

			if( (keyboardstate[ i ] & 128) != (g_keyboardstate[ i ] & 128) )
			{
				e.type = keyboardstate[ i ] & 128 ? glfEventKeyDown : glfEventKeyUp;
				e.key.scancode = i;
				glfPushEvent( &e );
			}
		}
	}
	memcpy( g_keyboardstate, keyboardstate, 256 * sizeof( BYTE ) );

	
	//Process mouse events
	rect.left = x;
	rect.top = y;
	rect.bottom = y+glfGetHeight()-1;
	rect.right = x+glfGetWidth()-1;
	mousestate.x = pt.x >= rect.left ? pt.x : rect.left;
	mousestate.y = pt.y >= rect.top ? pt.y : rect.top;
	mousestate.x = mousestate.x < rect.right ? mousestate.x : rect.right;
	mousestate.y = mousestate.y < rect.bottom ? mousestate.y : rect.bottom;
	mousestate.x -= x;
	mousestate.y -= y;
	mousestate.dx = pt.x - g_pt.x;
	mousestate.dy = pt.y - g_pt.y;
	
	if( mousestate.x != g_mousestate.x || mousestate.y != g_mousestate.y )
	{
		e.type = glfEventMouse;
		e.mouse.x = mousestate.x;
		e.mouse.y = mousestate.y;
		e.mouse.dx = mousestate.dx;
		e.mouse.dy = mousestate.dy;
		memcpy( &g_mousestate, &mousestate, sizeof( MouseState ) );
		memcpy( &g_pt, &pt, sizeof( POINT ) );
		glfPushEvent( &e );
	}
#endif

	return 1;
}